package com.wkbb.basic.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.wkbb.basic.enums.DeviceBoxOperateTypeEnum;
import com.wkbb.basic.feign.DoorFeignService;
import com.wkbb.basic.feign.WxFeignService;
import com.wkbb.basic.mapper.UserFaceMapper;
import com.wkbb.basic.mapper.UserFacePersonConfigMapper;
import com.wkbb.basic.mapper.YoutuFaceMapper;
import com.wkbb.basic.mapper.YoutuPersonMapper;
import com.wkbb.basic.model.*;
import com.wkbb.basic.service.*;
import com.wkbb.basic.thread.DeviceBoxTask;
import com.wkbb.basic.utils.FileUtil;
import com.wkbb.basic.utils.ImageOfbase64UtilDto;
import com.wkbb.basic.utils.WebankUtil;
import com.wkbb.basic.utils.YouTuUtil;
import com.wkbb.common.base.BaseServiceImpl;
import com.wkbb.common.config.ServiceConfig;
import com.wkbb.common.dto.ResultDTO;
import com.wkbb.common.dto.basic.UserDto;
import com.wkbb.common.dto.basic.UserFaceDto;
import com.wkbb.common.dto.wx.AccountDto;
import com.wkbb.common.enums.FaceTypeEnum;
import com.wkbb.common.redis.RedisTemplateUtil;
import com.wkbb.common.utils.ThreadPoolUtil;
import com.wkbb.common.utils.UuIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author luowenyan
 * @version V1.0
 * @className UserFaceServiceImpl
 * @description TODO
 * @date 2019/8/26 11:09
 */
@Service
@Slf4j
public class UserFaceServiceImpl extends BaseServiceImpl<UserFace> implements UserFaceService {
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;

    @Autowired
    private UserFaceMapper userFaceMapper;

    @Autowired
    private UserFacePersonConfigMapper userFacePersonConfigMapper;

    @Autowired
    private YouTuService youTuService;

    @Autowired
    private YoutuPersonMapper youtuPersonMapper;

    @Autowired
    private WxFeignService wxFeignService;

    @Autowired
    private WebankService webankService;

    @Autowired
    private UserOpenService userOpenService;

    @Autowired
    private DeviceBoxService deviceBoxService;

    @Autowired
    private YoutuFaceMapper youtuFaceMapper;

    @Autowired
    private WebankUtilService webankUtilService;

    @Autowired
    private DoorFeignService doorFeignService;

    @Autowired
    private ServiceConfig serviceConfig;

    @Autowired
    private OrganizationWebankService organizationWebankService;

    @Override
    public List<UserFaceDto> getUserFaceList(Long orgId, List<Long> classIds) {
        return userFaceMapper.getUserFaceList(orgId, classIds);
    }

    @Override
    public List<UserFaceDto> getUserFaceImgByOrg(Long orgId) {
        return userFaceMapper.getUserFaceImgByOrg(orgId);
    }

    @Override
    public void repairYouTu() {
        //先获取所有face_id为null的人脸
        List<UserFace> userFaceList = userFaceMapper.getUserFaceAndFaceIdIsNull();
        Map<String, Object> map = new HashMap<>(1);

        if (null != userFaceList && userFaceList.size() > 0) {

            try {

                log.error("-----------准备修复已存在个体的人脸数据----------");
                for (UserFace userFace : userFaceList) {

                    log.error("-----------当前正在修复的人脸对象----------userFace:{}", userFace);
                    map.put("personId", userFace.getPersonId());
                    List<UserFace> userFaceAndFaceIdNotIsNullList = userFaceMapper.getUserFaceAndFaceIdNotIsNull(map);

                    //获取当前上传人脸时的orgId,accountId,userId
                    YoutuPerson youtuPerson = youtuPersonMapper.getByMapParams(map);

                    if (null != youtuPerson) {
                        //如果当前用户有除faceId为空的脸,就传入2张图片对比,否则只传一张
                        if (null != userFaceAndFaceIdNotIsNullList && userFaceAndFaceIdNotIsNullList.size() > 0) {
                            String result = youTuService.addUserFace(new ImageOfbase64UtilDto(userFaceAndFaceIdNotIsNullList.get(0).getWebUrl(), FileUtil.encodeImageToBase64(new URL(userFaceAndFaceIdNotIsNullList.get(0).getWebUrl()))), userFace.getPersonId(), youtuPerson.getOrgId(), youtuPerson.getAccountId(), youtuPerson.getUserId());

                            if (null != JSONObject.parseObject(result).get("added")) {

                                //如果返回成功并且
                                if (YouTuUtil.ERRORCODETYPE.equals(JSONObject.parseObject(result).get("errorcode")) && new BigDecimal(JSONObject.parseObject(result).get("added").toString()).compareTo(new BigDecimal(0)) == 1) {
                                    userFace.setFaceId(JSONObject.parseObject(result).getJSONArray("face_ids").get(0).toString());
                                    userFaceMapper.update(userFace);

                                }
                            } else if (YouTuUtil.ERRORCODETYPE.equals(JSONObject.parseObject(result).get("errorcode"))) {
                                userFace.setFaceId(JSONObject.parseObject(result).get("face_id").toString());
                                userFaceMapper.update(userFace);

                            }
                        }
                    }
                }

            } catch (Exception e) {
                log.error("-----------修复已存在的个体人脸数据异常----------", e);
            }
        }
    }

    @Override
    @Transactional
    public void deleteFaceData(Long orgId) {
        //查询accountId
        ResultDTO<AccountDto> resultDto = wxFeignService.getAccountByOrg(orgId);
        log.info("---------deleteFaceData---------getAccountByOrg结果resultDto={}", resultDto);
        if (null == resultDto || !resultDto.isSuccess() || null == resultDto.getData()) {
            return;
        }
        //1.先删除优图中的人脸
        Long accountId = resultDto.getData().getId();
        if (null != accountId) {
            log.info("---------deleteFaceData---------参数:accountId={},orgId={}", accountId, orgId);
            List<Object> objects = youTuService.deletePersonByOrgId(orgId);
            log.info("---------deleteFaceData---------deleteOrgPerson结果objects={}", JSONObject.toJSONString(objects));
            if (null != objects && objects.size() == 0) {
                //2.开启批量处理,连接的URL后面加上&allowMultiQueries=true就可以了
                userFaceMapper.deleteFaceData(orgId);
            }
        }
    }

    @Override
    public List<YoutuPerson> getFaceData(Long orgId) {
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("orgId", orgId);
        return youtuPersonMapper.getListByMapParams(paramMap);
    }

    @Override
    public List<UserFacePersonConfig> getUserFacePersonConfigList(Map<String, Object> params) {
        return userFacePersonConfigMapper.getListByMapParams(params);
    }

    @Override
    public void saveUserFacePersonConfig(List<UserFacePersonConfig> userFacePersonConfigList) {
        userFacePersonConfigMapper.insertBatch(userFacePersonConfigList);
    }

    /**
     * 根据学校用户查询人脸信息
     *
     * @param params 机构用户ID
     * @return 人脸信息
     */
    @Override
    public UserDto getUserByOrgPerson(Map<String, Object> params) {
        return userFaceMapper.getUserByOrgPerson(params);
    }

    /**
     * 人脸录入（设备端注册人脸，不走云端注册）
     *
     * @param picUrlA
     * @param orgId
     * @param accountId
     * @param userId
     * @param type
     * @param similar
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addUserFace(String picUrlA, Long orgId, Long accountId, Long userId, Integer type, Short similar) {

        log.info("\n获取用户信息............ 开始..准备开始获取分布式锁......" + youTuService.getAddUserFaceLog(userId, orgId), userId);
        boolean lock = false;
        Boolean result = false;
        int retryCount = 0;
        while (!lock) {
            try {
                lock = redisTemplateUtil.tryLock(youTuService.getAddUserFaceRedisKey(userId, orgId), userId.toString(), 120, TimeUnit.SECONDS);
                log.info("#################" + youTuService.getAddUserFaceLog(userId, orgId), "加锁 ", userId.toString());

            } catch (Exception e) {
                log.error("#################加锁失败..等待锁过期 ：" + youTuService.getAddUserFaceLog(userId, orgId), userId);
                e.printStackTrace();
            }
            if (lock) {//加锁成功
                log.info("----------获取当前线程名称----------ThreadName:{}" + youTuService.getAddUserFaceLog(userId, orgId), userId, Thread.currentThread().getName());
                //判断当前用户在当前学校是否有注册人脸,如果没有人脸就注册person并且注册人脸,如果有一张就注册2张,如果有2张就不注册了
                log.info("---------准备注册人脸的学校ID和用户ID----------orgId:{},userId:{}", orgId, userId);
                log.info("---------addUserFace入参---------picUrla:{},orgId:{},accountId:{},userId:{}", picUrlA,  orgId, accountId, userId);
                //通过userCode获取个体是否创建
                YoutuPerson youtuPerson = youTuService.getYoutuPerson(orgId, userId);
                try {
                    if (null == youtuPerson) {
                        String newPersonId = webankService.createPersonId(userId);
                        //先注册到阅面算法。如果重复注册，会自动检测不处理，人脸有变化会自动更新。
                        ResultDTO<Object> resultDTO = doorFeignService.faceRegist(null,picUrlA,newPersonId,null,UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(orgId)));
                        if(!ResultDTO.checkSuccess(resultDTO)){
                            return false;
                        }

                        log.info("----------注册到阅面完成，创建person和face到数据库----------");
                        webankService.addWebankPerson( accountId, userId, orgId, newPersonId, picUrlA,type,similar);

                        log.info("--------创建个体结束:{},开始同步人脸信息到巨龙盒子:{}", result, youTuService.getAddUserFaceLog(userId, orgId));
                        //同步人脸信息到巨龙盒子
                        ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_ADD_PERSON.getCode(), deviceBoxService, newPersonId, picUrlA, orgId));
                        log.info("--------同步人脸信息到巨龙盒子结束,开始同步信息到xmpp--------" + youTuService.getAddUserFaceLog(userId, orgId));
                        //获取当前用户身份,同步信息到xmpp
                        userOpenService.xmppUpdatePersonByRole(orgId, userId);
                        log.info("--------同步信息到xmpp结束--------" + youTuService.getAddUserFaceLog(userId, orgId));
                        return true;
                    } else {
                        //后台业务重复提交,先删除人脸,再新增人脸
                        //先注册到阅面算法。如果重复注册，会自动检测不处理，人脸有变化会自动更新。
                        ResultDTO<Object> resultDTO = doorFeignService.faceRegist(null,picUrlA,youtuPerson.getPersonId(),null,UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(orgId)));
                        if(!ResultDTO.checkSuccess(resultDTO)){
                            return false;
                        }
                        return modifyFace(youtuPerson.getPersonId(), orgId, picUrlA, type, similar, userId);
                    }
                } catch (Exception e) {
                    log.error("---------添加人脸失败----------result:{}", result);
                    e.printStackTrace();
                } finally {
                    try {
                        youTuService.releaseLockAddUserFace(orgId, userId);
                    } catch (Exception e) {
                        log.info("#################释放锁失败..等待锁过期 ," + youTuService.getAddUserFaceLog(userId, orgId), userId);
                        e.printStackTrace();
                    }
                }

                log.info("---------打印人脸注册结果----------result:{}", result);

            } else {
                try {
                    retryCount++;
                    if (retryCount > 20) {
                        log.info("加锁失败，重试超过20次，新增IM账号失败...orgId:{}", orgId);
                        break;
                    }
                    log.info("等待500ms重试..." + youTuService.getAddUserFaceLog(userId, orgId), userId);
                    Thread.sleep(500L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

    /**
     * @param personId
     * @param orgId
     * @param picUrlA
     * @return result
     */
    @Override
    public Boolean modifyFace(String personId, Long orgId, String picUrlA, Integer type, Short similar, Long userId) {

        //查询数据库,如果有人脸,删除以前的人脸,再添加人脸
        Map<String, Object> params = new HashMap<>(1);
        params.put("personId", personId);
        YoutuFace newYouTuFace = youtuFaceMapper.getByMapParams(params);
        try {
            if (null != newYouTuFace) {

                YoutuPerson person = webankService.getYoutuPersonByParam(personId);

                youTuService.updateYouTuFace(person.getUserId(), orgId, personId, picUrlA, type, similar);


            } else {
                YoutuFace youtuFace = new YoutuFace();
                youtuFace.setPersonId(personId);

                youtuFace.setWebUrl(picUrlA);
                youtuFace.setFaceType(FaceTypeEnum.JUSTFACE.getValue().byteValue());
                youtuFace.setSourceType(YouTuUtil.SOURCETYPE);
                youtuFace.setWebankStatus(true);
                youtuFaceMapper.insert(youtuFace);

                webankService.checkPersonConfig(userId, orgId, type, similar, personId);
            }
        } catch (Exception e) {
            log.info("人脸修改失败JsonObject-{}", e.getMessage());
            return false;
        }

        try {
//            //在巨龙盒子删除相应人员
//            ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_DELETE_PERSON.getCode(), deviceBoxService, personId, null, orgId));

            //同步人脸到xmpp
            userOpenService.xmppUpdatePersonByRole(orgId, userId);

            //在巨龙盒子增加相应人员
            ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_ADD_PERSON.getCode(), deviceBoxService, personId, picUrlA, orgId));
        } catch (Exception e) {
            log.info("----------XMPP请求失败---------,e:{}", e.getMessage());
        }
        return true;
    }

    /**
     * @param personId
     * @return result
     */
    @Override
    public String deleteFace(String personId, Long orgId) {

        //查询数据库,如果有人脸,删除以前的人脸
        Map<String, Object> params = new HashMap<>(1);
        params.put("personId", personId);
        YoutuFace newYouTuFace = youtuFaceMapper.getByMapParams(params);
        try {
            if (null != newYouTuFace) {

                log.info("--------开始查询学校微众appid--------orgId:{}", orgId);
                OrganizationWebank organizationWebank = organizationWebankService.getOrganizationWebanksByOrgId(orgId, null);
                //在微众删除相应人员
                String result  = webankUtilService.delPerson(personId, false, organizationWebank.getWebankAppid(), organizationWebank.getWebankSecret(), orgId);

                ResultDTO<Object> resultDTO = doorFeignService.deleteFace(personId,null,UuIdUtil.getGroupIds(serviceConfig.getProfilesActive(), String.valueOf(orgId)));
                boolean webankResult = WebankUtil.checkIfSuccess(result);
                boolean readsenResult =ResultDTO.checkSuccess(resultDTO);
                //删除微众人脸的时候，若用户不存在，不予理会，不妨碍优图逻辑
                if (!WebankUtil.userNotExists(result)) {
                    //微众人脸删除失败，抛出异常终止人脸删除
                    if (!WebankUtil.checkIfSuccess(result)) {
                        log.error("删除微众人员失败:{}", webankResult);
                        return WebankUtil.getMessage(result);
                    }
                }

                YoutuPerson person = webankService.getYoutuPersonByParam(personId);

                if(readsenResult) {
                    youTuService.deleteYouTuFace(personId);
                }else{
                    log.info("人脸删除失败webank:{},readsenResult:{}", webankResult,readsenResult);
                    return resultDTO.getErrorMsg();
                }

                try {
                    //在巨龙盒子删除相应人员
                    ThreadPoolUtil.addPoolTask(new DeviceBoxTask(DeviceBoxOperateTypeEnum.BOX_OPERATE_DELETE_PERSON.getCode(), deviceBoxService, personId, null, person.getOrgId()));
                    //同步人脸到xmpp
                    userOpenService.xmppUpdatePersonByRole(person.getOrgId(), person.getUserId());
                } catch (Exception e) {
                    log.info("----------XMPP请求失败---------,e:{}", e.getMessage());
                }
            }
        } catch (Exception e) {
            log.info("人脸删除失败JsonObject-{}", e.getMessage());
            return "人脸删除异常";
        }


        return "人脸删除成功";
    }

    /**
     * @return result
     */
    @Override
    public List<UserFaceDto> getUserFaceListByUpdateTime(String beginTime, String endTime) {

        //查询数据库,一定时间范围内的所有人脸数据
        Map<String, Object> params = new HashMap<>(2);
        params.put("beginTime", beginTime);
        params.put("endTime", endTime);
        List<UserFaceDto> list = userFaceMapper.getUserFaceListByUpdateTime(params);

        return list;
    }
}